package com.vegetable.modules.finance.service;

import cn.hutool.crypto.asymmetric.RSA;
import cn.hutool.crypto.asymmetric.SignAlgorithm;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import lombok.extern.slf4j.Slf4j;
import com.vegetable.common.utils.HttpUtil;
import com.vegetable.modules.config.ChinaUMSConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.nio.charset.StandardCharsets;
import java.security.Signature;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.KeyFactory;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Base64;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;

/**
 * 银联商务代付业务代理服务
 * 实现银联商务代付业务接口的调用
 */
@Slf4j
@Service
public class ChinaUMSProxyService {
    
    @Autowired
    private ChinaUMSConfig chinaUMSConfig;
    
    /**
     * 生成待签名字符串
     * @param map 参数Map
     * @param excludeSign 是否排除sign参数
     * @return 待签名字符串
     */
    private String generateSortString(Map<String, String> map, boolean excludeSign) {
        if (map == null || map.isEmpty()) {
            return "";
        }
        
        // 创建新的Map，避免修改原Map
        Map<String, String> paramMap = new HashMap<>(map);
        
        // 如果需要排除sign参数
        if (excludeSign) {
            paramMap.remove("sign");
        }
        
        // 转换为TreeMap进行排序
        TreeMap<String, String> treeMap = new TreeMap<>(paramMap);
        
        // 拼接参数
        StringBuilder sb = new StringBuilder();
        for (Map.Entry<String, String> entry : treeMap.entrySet()) {
            String key = entry.getKey();
            String value = entry.getValue();
            
            // 排除空值参数
            if (value != null && !value.isEmpty()) {
                if (sb.length() > 0) {
                    sb.append("&");
                }
                sb.append(key).append("=").append(value);
            }
        }
        
        return sb.toString();
    }
    
    /**
     * SHA256WithRSA签名
     * @param data 待签名数据
     * @param privateKey 私钥
     * @return 签名结果
     */
    private String sign(byte[] data, String privateKey) throws Exception {
        byte[] keyBytes = Base64.getDecoder().decode(privateKey);
        PKCS8EncodedKeySpec pkcs8KeySpec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PrivateKey privateK = keyFactory.generatePrivate(pkcs8KeySpec);
        
        Signature signature = Signature.getInstance("SHA256WithRSA");
        signature.initSign(privateK);
        signature.update(data);
        return Base64.getEncoder().encodeToString(signature.sign());
    }
    
    /**
     * SHA256WithRSA验签
     * @param data 待验签数据
     * @param publicKey 公钥
     * @param sign 签名
     * @return 验签结果
     */
    private boolean verify(byte[] data, String publicKey, String sign) throws Exception {
        byte[] keyBytes = Base64.getDecoder().decode(publicKey);
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PublicKey publicK = keyFactory.generatePublic(keySpec);
        
        Signature signature = Signature.getInstance("SHA256WithRSA");
        signature.initVerify(publicK);
        signature.update(data);
        return signature.verify(Base64.getDecoder().decode(sign));
    }
    
    /**
     * 公钥加密
     * @param data 待加密数据
     * @param publicKey 公钥
     * @return 加密结果
     */
    private String encryptByPublicKey(String data, String publicKey) {
        RSA rsa = new RSA(null, publicKey);
        byte[] encryptedData = rsa.encrypt(data.getBytes(StandardCharsets.UTF_8), cn.hutool.crypto.asymmetric.KeyType.PublicKey);
        return cn.hutool.core.codec.Base64.encode(encryptedData);
    }
    
    /**
     * 私钥解密
     * @param encryptedData 已加密数据
     * @param privateKey 私钥
     * @return 解密结果
     */
    private String decryptByPrivateKey(String encryptedData, String privateKey) {
        RSA rsa = new RSA(privateKey, null);
        byte[] decryptedData = rsa.decrypt(cn.hutool.core.codec.Base64.decode(encryptedData), cn.hutool.crypto.asymmetric.KeyType.PrivateKey);
        return new String(decryptedData, java.nio.charset.StandardCharsets.UTF_8);
    }
    
    /**
     * 字节数组转16进制字符串
     * @param bytes 字节数组
     * @return 16进制字符串
     */
    private String toHexString(byte[] bytes) {
        StringBuilder sb = new StringBuilder();
        for (byte b : bytes) {
            sb.append(String.format("%02x", b));
        }
        return sb.toString();
    }
    
    /**
     * 16进制字符串转字节数组
     * @param hexString 16进制字符串
     * @return 字节数组
     */
    private byte[] toBytes(String hexString) {
        if (hexString == null || hexString.isEmpty()) {
            return new byte[0];
        }
        
        int len = hexString.length();
        byte[] data = new byte[len / 2];
        for (int i = 0; i < len; i += 2) {
            data[i / 2] = (byte) ((Character.digit(hexString.charAt(i), 16) << 4)
                    + Character.digit(hexString.charAt(i+1), 16));
        }
        return data;
    }
    
    /**
     * 单笔代付接口
     * @param params 业务参数
     * @param isProduction 是否生产环境
     * @return 响应结果
     */
    public Map<String, Object> singlePayment(Map<String, String> params, boolean isProduction) {
        try {
            // 构建基础参数
            Map<String, String> map = new HashMap<>();
            map.put("sysId", chinaUMSConfig.getSysId());
            map.put("sysOrderId", params.get("sysOrderId"));
            map.put("mchntNo", params.get("mchntNo"));
            map.put("responseUrl", params.get("responseUrl"));
            map.put("timestamp", new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()));
            map.put("revAcctName", params.get("revAcctName"));
            map.put("revIdCardNum", params.get("revIdCardNum"));
            map.put("revAcctNo", params.get("revAcctNo"));
            map.put("payAmt", params.get("payAmt"));
            map.put("remark", params.get("remark"));
            
            // 添加可选参数
            if (params.containsKey("verify")) {
                map.put("verify", params.get("verify"));
            }
            if (params.containsKey("mobilePhone")) {
                map.put("mobilePhone", params.get("mobilePhone"));
            }
            if (params.containsKey("termNo")) {
                map.put("termNo", params.get("termNo"));
            }
            if (params.containsKey("associateTransKey")) {
                map.put("associateTransKey", params.get("associateTransKey"));
            }
            if (params.containsKey("pyeeAcctTp")) {
                map.put("pyeeAcctTp", params.get("pyeeAcctTp"));
            }
            if (params.containsKey("pyerAcctTp")) {
                map.put("pyerAcctTp", params.get("pyerAcctTp"));
            }
            if (params.containsKey("pyeeBkId")) {
                map.put("pyeeBkId", params.get("pyeeBkId"));
            }
            if (params.containsKey("pyeeBkNo")) {
                map.put("pyeeBkNo", params.get("pyeeBkNo"));
            }
            
            // 开始签名
            String sign = sign(generateSortString(map, true).getBytes(StandardCharsets.UTF_8), chinaUMSConfig.getPrivateKey());
            map.put("sign", sign);
            
            // 开始加密
            String content = toHexString(encryptByPublicKey(JSON.toJSONString(map), chinaUMSConfig.getPublicKey()).getBytes(StandardCharsets.UTF_8));
            
            // 构建请求参数
            Map<String, String> requestParams = new HashMap<>();
            requestParams.put("content", content);
            requestParams.put("appSource", chinaUMSConfig.getSysId());
            requestParams.put("msgSrc", chinaUMSConfig.getMsgSrc());
            requestParams.put("msgType", "/singlepayment/process");
            
            // 构建POST请求体
            StringBuilder requestBody = new StringBuilder();
            for (Map.Entry<String, String> entry : requestParams.entrySet()) {
                if (requestBody.length() > 0) {
                    requestBody.append("&");
                }
                requestBody.append(entry.getKey()).append("=").append(entry.getValue());
            }
            
            // 发送请求
            String url = isProduction ? chinaUMSConfig.getProductionConfig().getSinglePaymentUrl() : chinaUMSConfig.getTest().getSinglePaymentUrl();
            String response = HttpUtil.post(url, requestBody.toString());
            
            // 解析响应
            Map<String, Object> result = new HashMap<>();
            result.put("requestParams", requestParams);
            result.put("response", response);
            return result;
        } catch (Exception e) {
            log.error("单笔代付接口调用失败", e);
            Map<String, Object> errorResult = new HashMap<>();
            errorResult.put("error", e.getMessage());
            return errorResult;
        }
    }
    
    /**
     * 单笔代付结果查询接口
     * @param sysOrderId 系统订单号
     * @param mchntNo 商户编号
     * @param trxDate 交易日期
     * @param isProduction 是否生产环境
     * @return 响应结果
     */
    public Map<String, Object> queryPaymentStatus(String sysOrderId, String mchntNo, String trxDate, boolean isProduction) {
        try {
            // 构建基础参数
            Map<String, String> map = new HashMap<>();
            map.put("sysId", chinaUMSConfig.getSysId());
            map.put("sysOrderId", sysOrderId);
            map.put("mchntNo", mchntNo);
            map.put("trxDate", trxDate);
            map.put("timestamp", new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()));
            
            // 开始签名
            String sign = sign(generateSortString(map, true).getBytes(StandardCharsets.UTF_8), chinaUMSConfig.getPrivateKey());
            map.put("sign", sign);
            
            // 开始加密
            String content = toHexString(encryptByPublicKey(JSON.toJSONString(map), chinaUMSConfig.getPublicKey()).getBytes(StandardCharsets.UTF_8));
            
            // 构建请求参数
            Map<String, String> requestParams = new HashMap<>();
            requestParams.put("content", content);
            requestParams.put("appSource", chinaUMSConfig.getSysId());
            requestParams.put("msgSrc", chinaUMSConfig.getMsgSrc());
            requestParams.put("msgType", "/singlepaymentresultstatus/process");
            
            // 构建POST请求体
            StringBuilder requestBody = new StringBuilder();
            for (Map.Entry<String, String> entry : requestParams.entrySet()) {
                if (requestBody.length() > 0) {
                    requestBody.append("&");
                }
                requestBody.append(entry.getKey()).append("=").append(entry.getValue());
            }
            
            // 发送请求
            String url = isProduction ? chinaUMSConfig.getProductionConfig().getQueryPaymentStatusUrl() : chinaUMSConfig.getTest().getQueryPaymentStatusUrl();
            String response = HttpUtil.post(url, requestBody.toString());
            
            // 解析响应
            Map<String, Object> result = new HashMap<>();
            result.put("requestParams", requestParams);
            result.put("response", response);
            return result;
        } catch (Exception e) {
            log.error("单笔代付结果查询接口调用失败", e);
            Map<String, Object> errorResult = new HashMap<>();
            errorResult.put("error", e.getMessage());
            return errorResult;
        }
    }
    
    /**
     * 可代付余额查询接口
     * @param mchntNo 商户编号
     * @param isProduction 是否生产环境
     * @return 响应结果
     */
    public Map<String, Object> queryPaymentBalance(String mchntNo, boolean isProduction) {
        try {
            // 构建基础参数
            Map<String, String> map = new HashMap<>();
            map.put("sysId", chinaUMSConfig.getSysId());
            map.put("mchntNo", mchntNo);
            map.put("timestamp", new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()));
            
            // 开始签名
            String sign = sign(generateSortString(map, true).getBytes(StandardCharsets.UTF_8), chinaUMSConfig.getPrivateKey());
            map.put("sign", sign);
            
            // 开始加密
            String content = toHexString(encryptByPublicKey(JSON.toJSONString(map), chinaUMSConfig.getPublicKey()).getBytes(StandardCharsets.UTF_8));
            
            // 构建请求参数
            Map<String, String> requestParams = new HashMap<>();
            requestParams.put("content", content);
            requestParams.put("appSource", chinaUMSConfig.getSysId());
            requestParams.put("msgSrc", chinaUMSConfig.getMsgSrc());
            requestParams.put("msgType", "/qrypaymentbalance/process");
            
            // 构建POST请求体
            StringBuilder requestBody = new StringBuilder();
            for (Map.Entry<String, String> entry : requestParams.entrySet()) {
                if (requestBody.length() > 0) {
                    requestBody.append("&");
                }
                requestBody.append(entry.getKey()).append("=").append(entry.getValue());
            }
            
            // 发送请求
            String url = isProduction ? chinaUMSConfig.getProductionConfig().getQueryPaymentBalanceUrl() : chinaUMSConfig.getTest().getQueryPaymentBalanceUrl();
            String response = HttpUtil.post(url, requestBody.toString());
            
            // 解析响应
            Map<String, Object> result = new HashMap<>();
            result.put("requestParams", requestParams);
            result.put("response", response);
            return result;
        } catch (Exception e) {
            log.error("可代付余额查询接口调用失败", e);
            Map<String, Object> errorResult = new HashMap<>();
            errorResult.put("error", e.getMessage());
            return errorResult;
        }
    }
    
    /**
     * 解密并验签响应结果
     * @param content 响应内容
     * @return 解密后的结果
     */
    public Map<String, Object> decryptAndVerify(String content) {
        try {
            // 解密（用外部平台私钥）
            String decryptStr = decryptByPrivateKey(content, chinaUMSConfig.getPrivateKey());
            Map<String, String> contentMap = JSON.parseObject(decryptStr, new TypeReference<Map<String, String>>(){});
            byte[] data = generateSortString(contentMap, true).getBytes(StandardCharsets.UTF_8);
            
            // 验签
            boolean isVerified = verify(data, chinaUMSConfig.getPublicKey(), contentMap.get("sign"));
            
            Map<String, Object> result = new HashMap<>();
            result.put("data", contentMap);
            result.put("verified", isVerified);
            return result;
        } catch (Exception e) {
            log.error("解密并验签失败", e);
            Map<String, Object> errorResult = new HashMap<>();
            errorResult.put("error", e.getMessage());
            return errorResult;
        }
    }
}